#ifndef __MGGS_ELEMENT_1D__
#define __MGGS_ELEMENT_1D__
#include <iostream>
#include <fstream>

/** 
 * One-dimensional points,including coordinate and index number.
 * 
 */
class Point_1
{
private:
    double *coord;
    int index;
public:
    Point_1();
    Point_1(double _x);
    Point_1(double _x, int _i);
    ~Point_1();
    Point_1(const Point_1 &_p);
    int get_index() const;
    void set_index(int _i);
    double get_coord() const;
    void set_coord(double _c);
    const Point_1& operator=(const Point_1 &_p);
    friend std::ostream& operator<<(std::ostream &_os, const Point_1 &_p);
    friend Point_1 operator+(const Point_1 &_p1, const Point_1 &_p2);
};

std::ostream& operator<<(std::ostream &_os, const Point_1 &_p);

Point_1 operator+(const Point_1 &_p1, const Point_1 &_p2);

/** 
 * One-dimensional interval,expressed by its left and right endpoints.
 * 
 */
class Interval
{
private:
    Point_1 a;
    Point_1 b;
public:
    Interval();
    Interval(const double _a, double _b);
    Interval(const Point_1 &_a, const Point_1 &_b);
    ~Interval();
    void set_a(const Point_1 &_p);
    void set_b(const Point_1 &_p);
    const Point_1& get_a();
    const Point_1& get_b();
    friend std::ostream& operator<<(std::ostream &_os, const Interval &_i);
};

std::ostream& operator<<(std::ostream& _os, const Interval& _i);

/** 
 * One-dimensional grid, generated with intervals.
 * 
 */
class Mesh_1
{
private:
  Interval *interval; /*Left and right borders of the mesh. */
  int n_grids; /*Number of intervals. */
  Interval *grids; /*Intervals generated the mesh. */
public:
  /** 
   * Generate mesh by intervals.
   * 
   * @param _grids Intervals used to generate the mesh.
   * @param _n_grids Number of intervals.
   */
    Mesh_1(const Interval *_grids, int _n_grids);
    /** 
     * Get intervals from points , then generate mesh.
     * 
     * @param _a Points used to generate intervals and mesh.
     * @param _n_nodes Number of points.
     */
    Mesh_1(const Point_1 *_a, int _n_nodes);
    ~Mesh_1();
    const Interval& get_interval();
    int get_n_grids();
    int get_n_nodes();
    /** 
     * Provide the _i-th interval of the mesh. Avoid extra copying 
     * by using intervals to generate mesh instead of points.
     * 
     * @param _i Index number of interval needed.
     * 
     * @return The _i-th interval of the mesh.
     */
    const Interval& get_element(int _i) const;
};

class Element_1_1
{
private:
    Point_1 a;
    Point_1 b;
    int n_dofs = 2;
public:
    Element_1_1();
    Element_1_1(const Point_1& _a, const Point_1& _b);
    ~Element_1_1();
    void set_a(const Point_1& _a);
    void set_b(const Point_1& _b);
    double phi_a(double _x);
    double phi_b(double _x);
};

/** 
 * An integration formula with its algebra accuracy and a table 
 * storing the integral points and integral weight of formula.
 *
 */
class Quad_Info
{
private:
  int accuracy; /*Algebra accuracy of formula. */
  int n_q_points; /*Number of integral points. */
  double **q_info; /*Information of integral points and corresponding 
                     integral weight. */
public:
    Quad_Info();
    void set(int _acc, int _n_q_pnts, double **_q_info);
    int get_accuracy() const;
    int get_n_q_points() const;
    /** 
     * Get the coordinate and integral weight of the _idx-th integral 
     * point.
     *
     * @param _idx Index of integral point.
     * 
     * @return Coordinate and integral weight of integral point.
     */
    const double* get_pAw(int _idx) const;
    ~Quad_Info();
};

/** 
 * Integral class with lots of integral formula.
 * 
 */
class Quad
{
private:
  int n_table; /*Number of integral formula in table. */
    Quad_Info *quad_info;
public:
    Quad();
    ~Quad();
    /** 
     * Get the integral table from file.
     * 
     * @param _file String of external file name.
     */
    void load_data(const char _file[]);
    int get_n_table() const;
    /** 
     * Get integral formula satisfying algebra accuracy _acc, and highest 
     * algebra accuracy formula if none of them satisfy.
     * 
     * @param _acc Algebra accuracy supposed to be satistied.
     * 
     * @return Formula satisfying algebra accuracy _acc, and highest 
     * algebra accuracy formula if none of them satisfy.
     */
    const Quad_Info& get_quad_info(int _acc) const;
    void list() const;
    double g2l(double _a, double _b, double _x) const;
    double l2g(double _a, double _b, double _t) const;
    double Jacobian(double _a, double _b) const;
};


#else
// DO NOTHING.
#endif
